package com.powernode.ssm.utils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 测试时遇到mapper文件识别不出来的问题，最终只能在resource文件夹下生成和java源码目录到dao目录
 * 相同的一系列路径
 *
 * 2025/11/04 新加逻辑：
 * 在生成每个文件前判断该文件是否存在，不存在则直接生成
 * 如果存在，则在后面追加新的代码，而不是直接覆盖
 */
public class GenMySqlCode {
    //从父目录到最后一层的上一层目录路径,作为文件生成路径
    private static String fileFromParent = ".ssm.src.main.java.com.powernode.ssm.";
    //mapper文件生成路径
    private static String mapperFromParent = ".ssm.src.main.resources.";
    //从java目录到最后一层的上一层目录路径,作为package路径
    private static String java2package = "com.powernode.ssm.";

    private final static String CONTROLLER = "controller";//controller包名
    private final static String SERVICE = "service";//service包名
    private final static String SERVICE_IMPL = "serviceImpl";//serviceImpl包名
    private final static String DAO = "dao";//dao包名
    private final static String POJO = "pojo";//实体类的包名
    private final static String VO = "vo";//请求实体类的包名
    private final static String BO = "bo";//响应实体类的包名
    private final static String PO = "po";//表对应实体类的包名
    private final static String UTILS = "utils";//表对应实体类的包名
    private final static String MAPPER = "mappers";//表对应实体类的包名 对应resources文件夹下面直接生成mappers文件夹
    private final static String MAPPER2 = "dao";//表对应实体类的包名2 对应java源码目录到dao目录的一系列路径

    public static void main(String[] args) throws IOException {
        String id = "TestPdf";//实体类名对应数据表
        String name = "测试pdf";//模块名
        String dataTable = "test4".toLowerCase();//数据库表名 注意大小写，需要完全一致

        String appCode = "B1098";
        //Controller类注解接口名称如@RequestMapping("/trade)
        String requestMappingName = "pdf";

        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/jdbc?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=utf8";
        String username = "root";
        String password = "123";
        String schema = "jdbc";//表所在数据库
        String databaseType = "";//数据库类型

        String[] split = driver.split("[.]");
        for (int i = 0; i < split.length; i++) {
            if ("mysql".equals(split[i])){
                databaseType = "mysql";
                System.out.println("==连接上了mysql数据库==");
            }else if ("postgresql".equals(split[i])){
                databaseType = "postgresql";
                System.out.println("==连接上了postgresql数据库==");
            }else if ("oracle".equals(split[i])){
                databaseType = "oracle";
                System.out.println("==连接上了oracle数据库==");
            }
        }

        if (databaseType.isEmpty()){
            System.out.println("==未知数据库，请检查==");
            return;
        }

        //是否生成增删改查标志
        boolean selectFlag = false;
        boolean insertFlag = true;
        boolean deleteFlag = true;
        boolean updateFlag = false;
        boolean importFlag = false;
        boolean exportFlag = false;

		//框架相关
		boolean isSwaggerFlag = true;
		boolean isMybatisPlusFlag = true;

        HashMap<String, StringBuilder> map = new HashMap<>();
        getContent(map, driver, url, username, password, dataTable, schema,isSwaggerFlag,isMybatisPlusFlag,databaseType);

        if (importFlag) {
            //生成导入请求实体类
            genImportVo(id, name);
            genImportBo(id, name, map);
            genListener(id);
        }
        if (exportFlag) {
            //生成导出用的实体类映射文件
            genExportBo(id, name, map);
        }

        genController(id, name , appCode, requestMappingName ,insertFlag,deleteFlag,updateFlag, selectFlag,importFlag,exportFlag);
        genService(id,insertFlag,deleteFlag, updateFlag,selectFlag,importFlag,exportFlag);
        genServiceImpl(id,insertFlag, deleteFlag,updateFlag, selectFlag,importFlag,exportFlag, name , map);
        genDao(id,insertFlag,deleteFlag, updateFlag, selectFlag,importFlag, exportFlag);
        genDeleteVo(id, name);
        genQueryVo(id, name , map);
        genSaveVo(id, name , map);
        genUpdateVo(id, name , map);
        genPo(id,dataTable, map);
        genBo(id, name , map);
        genMapper(id, dataTable, map,insertFlag, deleteFlag,updateFlag,selectFlag,importFlag, exportFlag,databaseType);
        System.out.println("==crud finish==");

        //打印导出模版文件内容，直接复制粘贴到excel中第一个单元格即可
        printlnTemp(map,appCode,name,requestMappingName);
    }

    private static void printlnTemp(HashMap<String, StringBuilder> map, String appCode, String name, String requestMappingName) {
        StringBuilder exportExcelTableHeadStrBuilder = map.get("exportExcelTableHeadStrBuilder");
        StringBuilder exportExcelTableExpressionStrBuilder = map.get("exportExcelTableExpressionStrBuilder");
        StringBuilder importExcelTableHeadStrBuilder = map.get("importExcelTableHeadStrBuilder");
        System.out.println();
        System.out.println("需要在高斯数据库(agent)和mysql数据库(maps)插入controller对应接口数据: ");
        System.out.println("例加: insert into h5_trx_ctl(appcode,trxcode,trxname,uri,zoneno, useflag,logflag)\n" +
                "VALUES ( "+appCode+"','"+appCode+"???','查询/増加/删除/修改/导入/导出 "+name+"'," +
                "'/"+requestMappingName+"/"+appCode+"???',2011,1,0)");
        System.out.println();
        System.out.println("生成的对应导入模板文件内容为:");
        System.out.println(importExcelTableHeadStrBuilder);
        System.out.println();
        System.out.println("生成的对应导出模板文件内容为:");
        System.out.println(exportExcelTableHeadStrBuilder);
        System.out.println(exportExcelTableExpressionStrBuilder);
    }

    private static void genMapper(String id, String dataTable, HashMap<String, StringBuilder> map, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag, String databaseType) throws IOException {
        String property = System.getProperty("user.dir");
        //在resources文件夹下生成mappers文件夹
        //String path = handleMapperPath(MAPPER);
        //在resources文件夹下继续生成从java源码文件夹到dao文件夹的一系列目录，最后命名为dao
        String path = handleMapperPath(java2package+MAPPER2);
        String absolutePath = property+path;

        //拼接select标签中查询的字段,即select a as a, b as b...
        //去除最后一个逗号
        String selectBuilder = map.get("selectBuilder").toString();
        int i = selectBuilder.lastIndexOf(",");
        selectBuilder = selectBuilder. substring(0,i);
        selectBuilder+="\n";

        //拼接insert标签中插入的字段,即insert into xxx(a,b...)
        //去除最后一个逗号
        String insertBuilder = map.get("insertBuilder"). toString();
        int j = insertBuilder.lastIndexOf(",");
        insertBuilder = insertBuilder. substring(0,j);

        //拼接insert标签中插入的foreach标签字段,即({item.a}.(item.b},...)
        //去除最后一个逗号
        String insertForeachBuilder = map. get("insertForeachBuilder").toString();
        int z = insertForeachBuilder.lastIndexOf( ",");
        insertForeachBuilder = insertForeachBuilder. substring(0,z);
        StringBuilder insertForeachItemBuilder = new StringBuilder();
        String[] split =insertForeachBuilder.split( ",");
        for (int i1 = 0;i1 < split.length; i1++) {
            String trim = split[i1].trim();
            if (i1 % 3 == 0) {
                trim = "#{item." + trim + "},\n\t\t\t\t";
            } else {
                trim = "#{item." + trim + "},";
            }
            insertForeachItemBuilder.append(trim);
        }
        //去除最后一个逗号
        int p = insertForeachItemBuilder.lastIndexOf(",");
        String insertForeachItemBuilderSubstring = insertForeachItemBuilder.substring(0, p);
        //拼接delete标签中
        String deleteStr = "    \n\t<delete id=\"delete"+id+"\">\n" +
                "        delete from "+dataTable+" g where id in (${item.ids})\n"+
                "    </delete>\n\n";
        //拼接update标签中插入的字段,即insert into xxx(a,b...)
        //去除最后一个逗号
        String updateBuilder = map.get("updateBuilder").toString();
        int u = updateBuilder.lastIndexOf( ",");
        updateBuilder = updateBuilder.substring(0,u);
        String updateStr =
                "   \t<update id=\"update"+id+"\">\n" +
                "        update "+dataTable+" g set\n" +
                        updateBuilder+
                "   \n\t\twhere id = #{item.id}\n"+
                "    </update>\n\n";
        String importStr = "";
        if ("mysql".equals(databaseType)){
            importStr =
                    "   \t<insert id=\"import"+id+"\" parameterType=\"java.util.List\">\n" +
                            "        insert ignore into "+dataTable+"("+insertBuilder+") values\n" +
                            "        <foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">\n" +
                            "           (\n\t\t\t\t" +insertForeachItemBuilderSubstring+ "\n" +
                            "           )\n" +
                            "        </foreach>\n"+
                            "   </insert>\n\n";

        }else if ("postgresql".equals(databaseType)){
            importStr =
                    "   \t<insert id=\"import"+id+"\" parameterType=\"java.util.List\">\n" +
                            "        insert into "+dataTable+"("+insertBuilder+") values\n" +
                            "        <foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">\n" +
                            "           (\n\t\t\t\t" +insertForeachItemBuilderSubstring+ "\n" +
                            "           )\n" +
                            "        </foreach>\n"+
                            "        ON DUPLICATE KEY\n"+
                            "        UPDATE\n" +
                            "        NOTHING\n"+
                            "   </insert>\n\n";
        }else if ("oracle".equals(databaseType)){
            System.out.println("该sql语法只适用于Oracle 12c+以上");
            importStr =
                    "   \t<insert id=\"import"+id+"\" parameterType=\"java.util.List\">\n" +
                            "        insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX("+dataTable+", "+"这里填该表的唯一索引key名如UK_MY_TABLE_ID"+") */ " +
                            "        into "+dataTable+"("+insertBuilder+") values\n" +
                            "        <foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">\n" +
                            "           (\n\t\t\t\t" +insertForeachItemBuilderSubstring+ "\n" +
                            "           )\n" +
                            "        </foreach>\n"+
                            "   </insert>\n\n";

        }
        String insertStr =
                "   \t<insert id=\"insert"+id+"\">\n"+
                "        insert into "+dataTable+" ("+insertBuilder+") values\n"+
                "            (\n\t\t\t\t" +insertForeachItemBuilderSubstring+ "\n" +
                "            )\n" +
                "     </insert>\n\n";
        String selectStr =
                        "   \t<select id=\"query"+id+"\" parameterType=\""+handlePackage(POJO+"."+VO)+".Query"+id+"Vo\"\n"+
                        "            resultType=\""+handlePackage(POJO+"."+PO+".")+id+"Po\">\n" +
                        "        SELECT " + selectBuilder +
                        "        FROM "+dataTable+" g\n" +
                        "        WHERE 1 = 1\n"+
                        "     </select>\n\n";
        String countStr =
                        "   \t<select id=\"count"+id+"\" resultType=\"java.lang.Integer\">\n"+
                        "        SELECT " + "count(1)\n" +
                        "        FROM "+dataTable+" g\n" +
                        "        WHERE 1 = 1\n" +
                        "     </select>\n\n";
        String mapper =
                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                        "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" " +
                        "\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n" +
                        "<mapper namespace=\"" + handlePackage(DAO + ".") + id + "Dao\">\n\n" +
                        addToMapper(selectStr, insertStr, deleteStr, updateStr, importStr, insertFlag, deleteFlag, updateFlag, selectFlag, importFlag) +
                        countStr +
                        "</mapper>\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("Mapper导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Dao.xml");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(mapper);
            fileWriter.flush();
            System.out.println("11、genMapper finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    addToMapper(selectStr, insertStr, deleteStr,
                            updateStr, importStr, insertFlag, deleteFlag,
                            updateFlag, selectFlag, importFlag)
                    +"\n";
            String targetString = "</mapper>";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("11、appendBo finish");
        }
    }

    private static String addToMapper(String selectStr, String insertStr, String deleteStr, String updateStr, String importStr, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag) {
        return  (selectFlag ? selectStr : "") +
                (insertFlag ? insertStr : "") +
                (deleteFlag ? deleteStr : "") +
                (updateFlag ? updateStr : "") +
                (importFlag ? importStr : "");
    }

    private static void genBo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder boBuilder = map.get("boBuilder");
        String property =System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+BO);
        String absolutePath = property+path;
        String bo =
                        "package "+handlePackage(POJO+"."+BO)+";\n\n"+
                        "import io.swagger.annotations.ApiModel; \n" +
                        "import io.swagger.annotations.ApiModelProperty;\n" +
                        "import lombok.*;\n\n" +
                        "import java.io.Serializable;\n\n"+
                        "@ApiModel(\""+name+ "响应体\")\n" +
                        "@Data\n" +
                        "@Builder\n" +
                        "@EqualsAndHashCode\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n"+
                        "public class "+id+"Bo implements Serializable {\n\n" +
                        boBuilder.toString()+
                        "\n" +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("实体类Bo导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Bo.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(bo);
            fileWriter.flush();
            System.out.println("10、genBo finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    boBuilder.toString()
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("10、appendBo finish");
        }
    }

    private static void genPo(String id, String dataTable, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder poBuilder = map.get("poBuilder");
        String property =System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+PO);
        String absolutePath = property+path;
        String po =
                    "package "+handlePackage(POJO+"."+PO)+";\n\n"+
                    "import com.baomidou.mybatisplus.annotation.TableField;\n"+
                    "import com.baomidou.mybatisplus.annotation.TableName;\n"+
                    "import lombok.AllArgsConstructor;\n" +
                    "import lombok.Data;\n" +
                    "import lombok.EqualsAndHashCode;\n"+
                    "import lombok.NoArgsConstructor;\n" +
                    "import lombok.experimental.Accessors;\n\n" +
                    "import java.io.Serializable;\n" +
                    "import java.math.BigDecimal;\n\n" +
                    "@Data\n"+
                    "@EqualsAndHashCode\n"+
                    "@Accessors(chain = true)\n" +
                    "@TableName(\""+dataTable+"\")\n"+
                    "@AllArgsConstructor\n" +
                    "@NoArgsConstructor\n" +
                    "public class "+id+"Po implements Serializable {\n\n" +
                    poBuilder.toString()+
                    "\n" +
                    "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("实体类Po导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Po.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("9、genPO finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    poBuilder.toString()
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("9、appendPO finish");
        }
    }

    private static void genUpdateVo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder boBuilder = map.get("boBuilder");
        String property =System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+VO);
        String absolutePath = property+path;
        String po =
                        "package "+handlePackage(POJO+"."+VO)+";\n\n"+
                        "import io.swagger.annotations.ApiModel;\n" +
                        "import io.swagger.annotations.ApiModelProperty;\n" +
                        "import lombok.AllArgsConstructor;\n" +
                        "import lombok.Builder;\n" +
                        "import lombok.Data;\n" +
                        "import lombok.NoArgsConstructor;\n" +
                        "import org.hibernate.validator.constraints.Length;\n\n" +
                        "import java.math.BigDecimal;\n\n\n"+
                        "@ApiModel(\"修改"+name+"请求体\")\n"+
                        "@Data\n"+
                        "@Builder\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n" +
                        "public class Update"+id+"Vo {\n\n"+
                        boBuilder.toString()+
                        "\n" +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("UpdateVo导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + "Update"+id + "Vo.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("6、genUpdateVo finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    boBuilder.toString()
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("6、appendUpdateVo finish");
        }
    }

    private static void genSaveVo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder boBuilder = map.get("boBuilder");
        String property =System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+VO);
        String absolutePath = property+path;
        String po =
                        "package "+handlePackage(POJO+"."+VO)+";\n\n"+
                        "import io.swagger.annotations.ApiModel;\n" +
                        "import io.swagger.annotations.ApiModelProperty;\n" +
                        "import lombok.AllArgsConstructor;\n" +
                        "import lombok.Builder;\n" +
                        "import lombok.Data;\n" +
                        "import lombok.NoArgsConstructor;\n" +
                        "import org.hibernate.validator.constraints.Length;\n\n" +
                        "import java.math.BigDecimal;\n\n\n"+
                        "@ApiModel(\"增加"+name+"请求体\")\n"+
                        "@Data\n"+
                        "@Builder\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n" +
                        "public class Save"+id+"Vo {\n\n"+
                        boBuilder.toString()+
                        "\n" +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("SaveVo导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + "Save"+id + "Vo.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("7、genSaveVo finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    boBuilder.toString()
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("7、appendSaveVo finish");
        }
    }

    private static void genQueryVo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder boBuilder = map.get("boBuilder");
        String property =System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+VO);
        String absolutePath = property+path;
        String po =
                        "package "+handlePackage(POJO+"."+VO)+";\n\n"+
                        "import io.swagger.annotations.ApiModel;\n" +
                        "import io.swagger.annotations.ApiModelProperty;\n" +
                        "import lombok.AllArgsConstructor;\n" +
                        "import lombok.Builder;\n" +
                        "import lombok.Data;\n" +
                        "import lombok.NoArgsConstructor;\n" +
                        "import org.hibernate.validator.constraints.Range;\n\n" +
                        "import javax.validation.constraints.NotNull;\n" +
                        "import java.math.BigDecimal;\n\n"+
                        "@ApiModel(\"查询"+name+"请求体\")\n"+
                        "@Data\n"+
                        "@Builder\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n" +
                        "public class Query"+id+"Vo {\n\n"+
                        boBuilder.toString()+
                        "\n\n" +
                        "   /**\n" +
                        "    * 当前页\n" +
                        "    */\n" +
                        "   @ApiModelProperty(value = \"当前页\")\n" +
                        "   @NotNull(message=\"翻页参数currentPage不能为空\")\n" +
                        "   private Integer currentPage = 1;\n\n"+
                        "   /**\n" +
                        "    * 当前页记录数\n" +
                        "    */\n" +
                        "   @NotNull(message=\"翻页参数size不能为空\")\n" +
                        "   @ApiModelProperty(value = \"当前页记录数\")\n" +
                        "   @Range(min = 1, max = 200, message = \"翻页参数pageSize不合法\")\n"+
                        "   private Integer pageSize = 30;\n\n" +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("QueryVo导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + "Query"+id + "Vo.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("6、QueryVo finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    boBuilder.toString()
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("6、appendQueryVo finish");
        }
    }

    private static void genDeleteVo(String id, String name) throws IOException {
        String property = System. getProperty("user.dir");
        String path = handleFilePath(POJO+"."+VO);
        String absolutePath = property+path;
        String po =
                        "package "+handlePackage(POJO+"."+VO)+";\n\n"+
                        "import io.swagger.annotations.ApiModel;\n"+
                        "import io.swagger.annotations.ApiModelProperty;\n"+
                        "import lombok.AllArgsConstructor;\n" +
                        "import lombok.Builder;\n" +
                        "import lombok.Data;\n"+
                        "import lombok.NoArgsConstructor;\n\n" +
                        "import javax.validation.constraints.NotNull;\n\n" +
                        "@ApiModel(\"删除"+name+"请求体\")\n" +
                        "@Data\n"+
                        "@Builder\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n" +
                        "public class Delete"+id+"Vo {\n\n"+
                        "   @NotNull(message=\"id不能为空\")\n" +
                        "   @ApiModelProperty(value = \"参数编号,例子 1,2,3,4\")\n"+
                        "   private String ids;\n\n"+
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("DeleteVo导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + "Delete"+id + "Vo.java");
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(po);
        fileWriter.flush();
        System.out.println("5、genDeleteVo finish");

    }

    private static void genDao(String id, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) throws IOException {
        String property = System. getProperty("user.dir");
        String path = handleFilePath(DAO);
        String absolutePath = property+path;

        String insertMethod = "     int insert"+id+"(@Param(\"item\") Save"+id+"Vo vo);\n\n";
        String deleteMethod = "     int delete"+id+"(@Param(\"item\") Delete"+id+"Vo vo);\n\n";
        String updateMethod = "     int update"+id+"(@Param(\"item\") Update"+id+"Vo vo);\n\n";
        String selectMethod = "     Page<"+id+"Po> query"+id+"(Page<?> page, @Param(\"item\") Query"+id+"Vo vo);\n\n";
        String importMethod = "     int import"+id+"(@Param(\"list\") List<"+id+"Po> list);\n\n";
        String countMethod  = "     int count"+id+"(@Param(\"id\") String id);\n\n";


        String dao =
                        "package " + handlePackage(DAO) + ";\n\n" +
                        "import com.baomidou.dynamic.datasource.annotation.DS;\n" +
                        "import com.baomidou.mybatisplus.core.mapper.BaseMapper;\n" +
                        "import com.baomidou.mybatisplus.extension.plugins.pagination.Page;\n" +
                        "import " + handlePackage(POJO + "." + VO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + PO) + ".*;\n" +
                        "import org.apache.ibatis.annotations.Param;\n" +
                        "import org.springframework.stereotype.Repository;\n" +
                        "import org.springframework.transaction.annotation.Transactional;\n" +
                        "import java.util.List;\n\n" +
                        "@Transactional\n" +
                        "@DS(\"mysql\")\n" +
                        "@Repository\n" +
                        "public interface " + id + "Dao extends BaseMapper<" + id + "Po> {\n\n" +
                        addToDao(selectMethod, insertMethod, deleteMethod, updateMethod, importMethod, insertFlag, deleteFlag, updateFlag, selectFlag, importFlag) +
                        countMethod +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("Dao导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Dao.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(dao);
            fileWriter.flush();
            System.out.println("4、genDao finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    addToDao(selectMethod, insertMethod, deleteMethod, updateMethod,
                            importMethod, insertFlag, deleteFlag, updateFlag,
                            selectFlag, importFlag)
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("4、appendDao finish");

        }

    }

    private static String addToDao(String selectMethod, String insertMethod, String deleteMethod, String updateMethod, String importMethod, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag) {
        return  (selectFlag ? selectMethod : "") +
                (insertFlag ? insertMethod : "") +
                (deleteFlag ? deleteMethod : "") +
                (updateFlag ? updateMethod : "") +
                (importFlag ? importMethod : "");
    }

    private static void genServiceImpl(String id, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag, String name, HashMap<String, StringBuilder> map) throws IOException {
        String sid = Character.toLowerCase(id. charAt(0)) + id.substring(1);
        String property = System.getProperty("user.dir");
        String path = handleFilePath(SERVICE_IMPL);
        String absolutePath = property+path;
        String insertImpl =
                        "   @Override\n"+
                        "   public ResponseUtils save"+id+" (Save"+id+"Vo save"+id+"Vo) {\n\n" +
                        "       String id = save"+id+"Vo.getId();\n"+
                        "       int num = "+sid+"Dao.count"+id+"(id);\n" +
                        "       if (num>0){\n"+
                        "           return new ResponseUtils<>(ReturnCodeEnum.SAME_RECORD_ERR.getCode(), "+
                                "ReturnCodeEnum.SAME_RECORD_ERR.getMsg(), null);\n"+
                        "       }\n" +
                        "       "+sid+"Dao.insert"+id+"(save"+id+"Vo);" +
                        "\n\n" +
                        "       springUtils.saveLog(\"插入"+name+"数据\");\n" +
                        "       return new ResponseUtils<>(ReturnCodeEnum.SUCCESS.getCode(), ReturnCodeEnum." +
                                "SUCCESS.getMsg(), null);\n"+
                        "   }\n\n";
        String deleteImpl =
                        "   @Override\n" +
                        "   public ResponseUtils batchDelete"+id+"(Delete"+id+"Vo delete"+id+"Vo) {\n\n" +
                        "       "+sid+"Dao.delete"+id+"(delete"+id+"Vo);" +
                        "\n\n" +
                        "       springUtils.saveLog(\"删除"+name+"数据\");\n" +
                        "       return new ResponseUtils<>(ReturnCodeEnum.SUCCESS.getCode(), "+
                                "ReturnCodeEnum.SUCCESS.getMsg(), null);\n"+
                        "   }\n\n";
        String updateImpl =
                        "   @Override\n"+
                        "   public ResponseUtils update"+id+" (Update"+id+"Vo update"+id+"Vo) {\n\n" +
                        "       String id = update"+id+"Vo.getId();\n" +
                        "       int num = "+sid+"Dao.count"+id+"(id);\n" +
                        "       if (num==0){\n" +
                        "           return new ResponseUtils<>(ReturnCodeEnum.APPINFO_NOT_FOUND.getCode(), "+
                                "ReturnCodeEnum.APPINFO_NOT_FOUND.getMsg(),null);\n" +
                        "       }\n"+
                        "       "+sid+"Dao.update"+id+"(update"+id+"Vo);" +
                        "\n\n"+
                        "       springUtils.saveLog(\"更新"+name+"数据\");\n" +
                        "       return new ResponseUtils<>(ReturnCodeEnum.SUCCESS.getCode(), " +
                                "ReturnCodeEnum.SUCCESS.getMsg(),null);\n"+
                        "   }\n\n";
        String selectImpl =
                        "   @Override\n"+
                        "   public ResponseUtils query"+id+" (Query"+id+"Vo query"+id+"Vo) {\n" +
                        "\n" +
                        "       int current = query"+id+"Vo.getCurrentPage();\n"+
                        "       int size = query"+id+"Vo.getPageSize();\n" +
                        "\n" +
                        "        Page<"+id+"Po> page = "+sid+"Dao.query"+id+"(\n" +
                        "               new Page<>(current, size), query"+id+"Vo);\n"+
                        "\n"+
                        "        PageBo pageBo = PageBo.builder()\n" +
                        "               .current(current)\n" +
                        "               .size(size)\n" +
                        "               .total(page.getTotal())\n" +
                        "               .dataList(page.getRecords())\n"+
                        "               .build();\n\n"+
                        "       return new ResponseUtils<>(ReturnCodeEnum.SUCCESS.getCode()," +
                                "ReturnCodeEnum.SUCCESS.getMsg(),pageBo);\n"+
                        "   }\n\n";
    String exportImpl =
                    "   @Override\n" +
                    "   public ResponseUtils exportEasyExcelWithTemplate(HttpServletResponse httpServletResponse, H5UserinfoPo h5UserinfoPo, "+
                            "Query"+id+"Vo item) {\n\n" +
                    "       int current = item.getCurrentPage();\n" +
                    "       int size = item.getPageSize();\n" +
                    "       String tempPathFileName =\"测试模版的文件名称\";//需要修改\n" +
                    "       String exportPathFileName = \"export\";//导出到前端的文件名称,需要修改,最好使用英文,中文可能解析不了\n" +
                    "       String suffix = \".xlsx\";//后缀名\n\n" +
                    "       List<"+id+"Po> data = "+sid+"Dao.query"+id+"(\n" +
                    "               new Page<>(current, size), item).getRecords();\n" +
                    "\n" +
                    "       ArrayList<Export"+id+"Bo> bos =new ArrayList<>();\n" +
                    "       if (ArrayUtil.isNotEmpty(data)){\n" +
                    "           data.forEach(item1 -> {\n" +
                    "               Export"+id+"Bo bo = BeanUtil.copyProperties(item1, Export"+id+"Bo.class);\n" +
                    "               bos.add(bo);\n" +
                    "           });\n" +
                    "       }\n\n"+
                    "       File file = FileUtil.file(exportPath);\n"+
                    "       file.mkdirs();\n" +
                    "       //导出excel到指定服务器目录\n"+
                    "       String excelPath = ImportAndExportUtils.exportEasyExcelWithTemplate(\n" +
                    "               tempPath + File.separator + tempPathFileName + suffix,\n" +
                    "               exportPath + File.separator + exportPathFileName + suffix,\n" +
                    "               bos);\n\n" +
                    "       //读取导出到指定服务器目录的excel返回输出流给前端\n"+
                    "       ImportAndExportUtils.export(httpServletResponse, h5UserinfoPo,encrypt,\n" +
                    "               excelPath.substring(0,excelPath.lastIndexOf(\".\")), suffix);\n\n"+
                    "       springUtils.saveLog(\"导出"+name+"数据\");\n" +
                    "       return null;\n" +
                    "   }\n\n";

        String importImpl =
                        "   @Override\n" +
                        "   public ResponseUtils importEasyExcelWithTemplate(Import"+id+"Vo import"+id+"Vo, H5UserinfoPo h5UserinfoPo) {\n"+
                        "        InputStream inputStream = null;\n" +
                        "        String msg = \"\";\n" +
                        "        try {\n" +
                        "             inputStream = import"+id+"Vo.getFile().getInputStream();\n"+
                        "             "+id+"Listener "+sid+"Listener = new "+id+"Listener("+sid+"Dao, h5UserinfoPo);\n" +
                        "             //第二个实体类参数需要加上@ExcelProperty(index = 0,value = \"xxx\")注解\n" +
                        "             EasyExcel.read(inputStream, Import"+id+"Bo.class,"+sid+"Listener).sheet(0).doRead();\n" +
                        "             msg = "+sid+"Listener.getMsg();\n" +
                        "        }catch (NoSuchBeanDefinitionException e){\n" +
                        "           e.printStackTrace();\n" +
                        "           return new ResponseUtils<>(ReturnCodeEnum.IMPORT_FIELD_EMPTY_ERR.getCode(), \n" +
                        "            ReturnCodeEnum.IMPORT_FIELD_EMPTY_ERR.getMsg(), null);\n" +
                        "        }catch (NoSuchElementException e){\n"+
                        "           e.printStackTrace();\n" +
                        "           return new ResponseUtils<>(ReturnCodeEnum.IMPORT_FORMAT_OR_EMPTY_ERR.getCode(),\n" +
                        "                   ReturnCodeEnum.IMPORT_FORMAT_OR_EMPTY_ERR.getMsg(), null);\n"+
                        "        }catch (Exception e) {\n" +
                        "           e.printStackTrace();\n"+
                        "           return new ResponseUtils<>(ReturnCodeEnum.IMPORT_FILE_ERR.getCode(), "+
                                "ReturnCodeEnum.IMPORT_FILE_ERR.getMsg(), null);\n"+
                        "        }\n" +
                        "        finally {\n"+
                        "            if(inputStream!=null){\n" +
                        "                try {\n" +
                        "                    inputStream.close();\n" +
                        "                } catch (IOException e) {\n"+
                        "                    e.printStackTrace();\n"+
                        "                }\n" +
                        "            }\n" +
                        "        }\n\n" +
                        "        springUtils.saveLog(\"导入"+name+"数据\");\n" +
                        "        return new ResponseUtils<>(ReturnCodeEnum.SUCCESS.getCode(), msg, null);\n"+
                        "    }\n\n";
        String po =
                        "package " + handlePackage(SERVICE_IMPL) + ";\n\n" +
                        "import cn.hutool.core.bean.BeanUtil;\n" +
                        "import cn.hutool.core.io.FileUtil; \n" +
                        "import cn.hutool.core.util.ArrayUtil;\n" +
                        "import com.alibaba.excel.EasyExcel;\n" +
                        "import com.baomidou.mybatisplus.extension.plugins.pagination.Page; \n" +
                        "import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n" +
                        "import " + handlePackage(DAO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + VO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + PO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + BO) + ".*;\n" +
                        "import " + handlePackage(SERVICE) + ".*;\n" +
                        "import " + handlePackage(UTILS) + ".*;\n" +
                        "import lombok.extern.slf4j.Slf4j;\n" +
                        "import org.springframework.beans.factory.NoSuchBeanDefinitionException;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired; \n" +
                        "import org.springframework.beans.factory.annotation.Value;\n" +
                        "import org.springframework.stereotype.Service;\n\n" +
                        "import javax.servlet.http.HttpServletResponse;\n" +
                        "import java.io.*;\n" +
                        "import java.util.ArrayList;\n" +
                        "import java.util.List;\n" +
                        "import java.util.NoSuchElementException;\n\n" +
                        "@Slf4j\n" +
                        "@Service\n" +
                        "public class " + id + "ServiceImpl extends ServiceImpl<" + id + "Dao, " + id + "Po> implements " + id + "Service {\n\n" +
                        "   @Autowired\n" +
                        "   " + id + "Dao " + sid + "Dao;\n\n" +
                        "   @Autowired\n" +
                        "   private SpringUtils springUtils;\n\n" +
                        "   @Value(\"${export.template_path}\")\n" +
                        "   private String tempPath;\n" +
                        "   @Value(\"${export.exportPath}\")\n" +
                        "   private String exportPath; \n\n" +
                        "   @Value(\"${export.dsp}\")\n" +
                        "   private boolean encrypt;\n\n" +
                        addToServiceImpl(selectImpl, updateImpl, insertImpl, deleteImpl, exportImpl, importImpl, insertFlag, deleteFlag, updateFlag, selectFlag, importFlag, exportFlag) +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("ServiceImpl导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "ServiceImpl.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("3、genServiceImpl finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    addToServiceImpl(selectImpl, updateImpl, insertImpl, deleteImpl, 
                            exportImpl, importImpl, insertFlag, deleteFlag, updateFlag, 
                            selectFlag, importFlag, exportFlag) 
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("3、appendServiceImpl finish");
        }

    }

    private static String addToServiceImpl(String selectImpl, String updateImpl, String insertImpl, String deleteImpl, String exportImpl, String importImpl, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) {
        return  (selectFlag ? selectImpl : "") +
                (updateFlag ? updateImpl : "") +
                (insertFlag ? insertImpl : "") +
                (deleteFlag ? deleteImpl : "") +
                (exportFlag ? exportImpl : "") +
                (importFlag ? importImpl : "");
    }

    private static void genExportBo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder exportBoBuilder = map.get("exportBoBuilder");
        String property = System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+BO);
        String absolutePath = property+path;
        String bo =
                        "package "+handlePackage(POJO+"."+BO)+";\n\n"+
                        "import com.alibaba.excel.annotation.ExcelProperty;\n" +
                        "import io.swagger.annotations.ApiModel;\n" +
                        "import lombok.*;\n\n" +
                        "import java.io.Serializable;\n\n" +
                        "@ApiModel(\""+name+"利用easyExcel导出excel响应体\")\n" +
                        "@Data\n" +
                        "@Builder\n" +
                        "@EqualsAndHashCode\n" +
                        "@NoArgsConstructor\n" +
                        "@AllArgsConstructor\n" +
                        "public class Export"+id+"Bo implements Serializable {\n\n" +
                        exportBoBuilder.toString()+
                        "\n" +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("easyExcel导出excel实体类Bo目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + "Export"+id + "Bo.java");
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(bo);
        fileWriter.flush();
        System.out.println("genEasyExcelExportBo finish");

    }

    private static void genService(String id, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) throws IOException {
        String property = System.getProperty("user.dir");
        String path = handleFilePath(SERVICE);
        String absolutePath= property+path;
        String selectInterFace = "  ResponseUtils query"+id+"(Query"+id+"Vo item);\n\n";
        String updateInterFace = "  ResponseUtils update"+id+"(Update"+id+"Vo update"+id+"Vo);\n\n";
        String insertInterFace = "  ResponseUtils save"+id+"(Save"+id+"Vo save"+id+"Vo);\n\n";
        String deleteInterFace = "  ResponseUtils batchDelete"+id+"(Delete"+id+"Vo delete"+id+"Vo);\n\n";
        String exportInterFace =
                "  ResponseUtils exportEasyExcelWithTemplate(HttpServletResponse httpServletResponse, \n" +
                "                                               H5UserinfoPo h5UserinfoPo, \n" +
                "                                               Query"+id+"Vo item);\n\n";
        String importInterFace =
                "  ResponseUtils importEasyExcelWithTemplate(Import"+id+"Vo import"+id+"Vo,\n" +
                "                                            H5UserinfoPo h5UserinfoPo);\n\n";
        String po =
                        "package " + handlePackage(SERVICE) + ";\n\n" +
                        "import " + handlePackage(POJO + "." + VO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + PO) + ".*;\n" +
                        "import " + handlePackage(UTILS) + ".ResponseUtils;\n" +
                        "import javax.servlet.http.HttpServletResponse;\n\n" +
                        "public interface " + id + "Service {\n\n" +
                        addToService(selectInterFace, updateInterFace, insertInterFace, 
                                deleteInterFace, exportInterFace, importInterFace, 
                                insertFlag, deleteFlag, updateFlag, selectFlag, importFlag, exportFlag) +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("Service导出目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Service.java");
        if (!file.exists()){
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("2、genService finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    addToService(selectInterFace, updateInterFace, insertInterFace, deleteInterFace, exportInterFace, importInterFace, insertFlag, deleteFlag, updateFlag, selectFlag, importFlag, exportFlag) 
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));
            System.out.println("2、appendService finish");

        }


    }

    private static String addToService(String selectInterFace, String updateInterFace, String insertInterFace, String deleteInterFace, String exportInterFace, String importInterFace, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) {
        return (selectFlag ? selectInterFace : "") +
                (updateFlag ? updateInterFace : "") +
                (insertFlag ? insertInterFace : "") +
                (deleteFlag ? deleteInterFace : "") +
                (exportFlag ? exportInterFace : "") +
                (importFlag ? importInterFace : "");
    }

    private static void genController(String id, String name, String appCode, String requestMappingName, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) throws IOException {
        String sid = Character.toLowerCase(id.charAt(0)) + id.substring(1);
        String property = System.getProperty("user.dir");
        String path = handleFilePath(CONTROLLER);
        String absolutePath = property+path;
        String insertEnter =
                        "   @ApiOperation(\"増加"+name+"\")\n"+
                        "   @RequestMapping(value = \"/"+appCode+"**\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils save"+id+" (@Validated @RequestBody "+
                                "Save"+id+"Vo save"+id+"Vo){\n" +
                        "        H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "        return "+sid+"Service.save"+id+"(save"+id+"Vo);\n"+
                        "   }\n\n";

        String deleteEnter =
                        "   @ApiOperation(\"批量删除"+name+"\")\n" +
                        "   @RequestMapping(value = \"/"+appCode+"**\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils batchDelete"+id+"(@Validated @RequestBody "+
                                "Delete"+id+"Vo delete"+id+"Vo){\n" +
                        "       H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "       return "+sid+"Service.batchDelete"+id+"(delete"+id+"Vo);\n" +
                        "   }\n\n";
        String updateEnter =
                        "   @ApiOperation(\"更新"+name+"\") \n" +
                        "   @RequestMapping(value = \"/"+appCode+"**\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils update"+id+"(@Validated @RequestBody Update"
                                +id+"Vo update"+id+"Vo){\n" +
                        "       H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "       return "+sid+"Service.update"+id+"(update"+id+"Vo);\n" +
                        "   }\n\n";
        String selectEnter =
                        "   @ApiOperation(\"查询"+name+"\")\n" +
                        "   @RequestMapping(value = \"/"+appCode+"**\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils query"+id+"(@Validated @RequestBody Query"
                                +id+"Vo query"+id+"Vo){\n" +
                        "       H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "       return "+sid+"Service.query"+id+"(query"+id+"Vo);\n"+
                        "   }\n\n";
        String exportEnter =
                        "   @ApiOperation(\"easyExcel导出"+name+"\")\n" +
                        "   @RequestMapping(value = \"/"+appCode+"**\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils export"+id+"(HttpServletResponse httpServletResponse, \n"+
                        "                                                @Validated @RequestBody Query"+id+"Vo query" +id+"Vo){\n" +
                        "       H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "       return "+sid+"Service.exportEasyExcelWithTemplate(httpServletResponse,"+
                                "h5UserinfoPo, query"+id+"Vo) ;\n" +
                        "   }\n\n";
        String importEnter =
                        "   @ApiOperation(\"easyExcel导入"+name+"\")\n" +
                        "   @RequestMapping(value = \"/"+appCode+"*\",method = RequestMethod.POST)\n" +
                        "   public ResponseUtils import"+id+"(@Validated Import"+id+"Vo import"+id+"Vo){\n" +
                        "       H5UserinfoPo h5UserinfoPo = springUtils.getUserByToken(ThreadLocalContext.getToken());\n"+
                        "       return "+sid+"Service.importEasyExcelWithTemplate(import"+id+"Vo,h5UserinfoPo);\n" +
                        "   }\n\n";

        String controller =
                        "package " + handlePackage(CONTROLLER) + ";\n\n" +
                        "import " + handlePackage(POJO + "." + VO) + ".*;\n" +
                        "import " + handlePackage(POJO + "." + PO) + ".*;\n" +
                        "import " + handlePackage(UTILS) + ".*;\n" +
                        "import " + handlePackage(SERVICE + ".") + id + "Service;\n" +
                        "import io.swagger.annotations.Api;\n" +
                        "import io.swagger.annotations.ApiOperation;\n" +
                        "import org.springframework.beans.factory.annotation.Autowired;\n" +
                        "import org.springframework.validation.annotation.Validated;\n" +
                        "import org.springframework.web.bind.annotation.RequestBody;\n" +
                        "import org.springframework.web.bind.annotation.RequestMapping;\n" +
                        "import org.springframework.web.bind.annotation.RequestMethod; \n" +
                        "import org.springframework.web.bind.annotation.RestController;\n" +
                        "import javax.servlet.http.HttpServletResponse;\n\n" +
                        "@Api(\n" +
                        "       value =\"" + name + "\",\n" +
                        "       tags = {\"" + name + "\"})\n\n" +
                        "@RestController\n" +
                        "@RequestMapping(\"/" + requestMappingName + "\")\n" +
                        "public class " + id + "Controller {\n\n" +
                        "   @Autowired\n" +
                        "   private " + id + "Service " + sid + "Service;\n\n" +
                        "   @Autowired\n" +
                        "   private SpringUtils springUtils;\n\n" +
                        addToController(selectEnter, insertEnter, updateEnter,
                                deleteEnter, exportEnter, importEnter, insertFlag,
                                deleteFlag, updateFlag, selectFlag, importFlag, exportFlag) +
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("Controller导入目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Controller.java");
        //判断文件是否已经存在
        if (!file.exists()){
            //第一次生成该文件
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(controller);
            fileWriter.flush();
            System.out.println("1、genController finish");
        }else {
            //文件已存在，追加内容
            String linesToInsert = "\n"+
                    addToController(selectEnter, insertEnter, updateEnter, deleteEnter, exportEnter, importEnter, insertFlag, deleteFlag, updateFlag, selectFlag, importFlag, exportFlag)
                    +"\n";
            String targetString = "}";
            insertLinesAfterFirstMatchFromEnd(file.getPath(), targetString, Collections.singletonList(linesToInsert));

            System.out.println("1、appendController finish");
        }

    }

    private static String addToController(String selectEnter, String insertEnter, String updateEnter, String deleteEnter, String exportEnter, String importEnter, boolean insertFlag, boolean deleteFlag, boolean updateFlag, boolean selectFlag, boolean importFlag, boolean exportFlag) {
        return (selectFlag ? selectEnter : "") +
                (insertFlag ? insertEnter : "") +
                (updateFlag ? updateEnter : "") +
                (deleteFlag ? deleteEnter : "") +
                (exportFlag ? exportEnter : "") +
                (importFlag ? importEnter : "");
    }

    private static void genListener(String id) throws IOException {
        String sid = Character.toLowerCase(id.charAt(0)) + id.substring(1);
        String property = System.getProperty("user.dir");
        String path = handleFilePath(UTILS);
        String absolutePath = property+path;
        String str =
                        "package "+handlePackage(UTILS)+";\n\n"+
                        "import cn.hutool.core.bean.BeanUtil; \n" +
                        "import cn.hutool.core.util.ClassUtil; \n"+
                        "import com.alibaba.excel.context.AnalysisContext;\n" +
                        "import com.alibaba.excel.event.AnalysisEventListener;\n" +
                        "import "+handlePackage(DAO)+".*;\n"+
                        "import "+handlePackage(POJO+"."+VO)+".*;\n"+
                        "import "+handlePackage(POJO+"."+PO)+".*;\n"+
                        "import "+handlePackage(POJO+"."+BO)+".*;\n"+
                        "import lombok.SneakyThrows;\n"+
                        "import lombok.extern.slf4j.Slf4j;\n"+
                        "import org.springframework.beans.factory.NoSuchBeanDefinitionException;\n"+
                        "import org.springframework.stereotype.Component; \n\n"+
                        "import java.lang.reflect.Field; \n" +
                        "import java.util.ArrayList;\n" +
                        "import java.util.List;\n" +
                        "import java.util.NoSuchElementException;\n\n"+
                        "@Component\n" +
                        "@Slf4j\n" +
                        "public class "+id+"Listener extends AnalysisEventListener<Import"+id+"Bo> {\n\n" +
                        "   private "+id+"Dao "+sid+"Dao;\n"+
                        "   private H5UserinfoPo h5UserinfoPo; \n" +
                        "   private int batchSize = getBatchSize("+id+"Po.class);//ー次批量插入数据量\n" +
                        "   private String msg = \"\";//是否有重复的提示\n" +
                        "   List<"+id+"Po> list= new ArrayList<>();\n" +
                        "   private int insertCount = 0;//重复的记录\n" +
                        "   private int sumCount = 0;//导入的记录数\n" +
                        "\n" +
                        "   public "+id+"Listener(){\n"+
                        "   }\n"+
                        "\n" +
                        "   public "+id+"Listener("+id+"Dao "+sid+"Dao, H5UserinfoPo h5UserinfoPo) {\n"+
                        "       this."+sid+"Dao = "+sid+"Dao;\n" +
                        "       this.h5UserinfoPo =h5UserinfoPo;\n" +
                        "   }\n" +
                        "\n"+
                        "@SneakyThrows\n" +
                        "@Override\n" +
                        "public void invoke(Import"+id+"Bo import"+id+"Bo, AnalysisContext analysisContext) {\n" +
                        "       //如果上传文件中存在一个空的单元格,就要报错\n"+
                        "       Field[] declaredFields = import"+id+"Bo. getClass().getDeclaredFields();\n"+
                        "       int nullNum = 0;\n" +
                        "       for (Field declaredField : declaredFields) {\n" +
                        "           declaredField.setAccessible(true);\n" +
                        "           if (declaredField.get(import"+id+"Bo)==null){\n" +
                        "               nullNum++;\n" +
                        "           }\n" +
                        "       }\n" +
                        "       //判断是否大于固定为nul1的字段数0\n"+
                        "       if (nullNum>0){\n" +
                        "           throw new NoSuchBeanDefinitionException(\"上传文件中不能存在空的单元格或未按照模板导入\");\n" +
                        "       }\n" +
                        "\n" +
                        "       "+id+"Po "+sid+"Po = BeanUtil.copyProperties(import"+id+"Bo, "+id+"Po.class);\n" +
                        "\n"+
                        "       list.add("+sid+"Po);\n" +
                        "       sumCount++;\n" +
                        "   }\n" +
                        "\n" +
                        "   @Override\n" +
                        "   public void doAfterAllAnalysed(AnalysisContext analysisContext) {\n" +
                        "\n"+
                        "       log.info(\"{}的一次批量插入数据量为{}\",\n" +
                        "       ClassUtil.getClassName(this.getClass(),true), \n" +
                        "       batchSize);\n"+
                        "\n"+
                        "       int size = list.size();\n" +
                        "\n"+
                        "       if (size==0){\n"+
                        "           throw new NoSuchElementException(\"上传文件格式错误或者数据为空\");\n" +
                        "       }\n"+
                        "\n"+
                        "\n"+
                        "        //todo 根据业务需要去重\n" +
                        "\n" +
                        "        ArrayList<"+id+"Po> subList = new ArrayList<>();\n" +
                        "\n"+
                        "       //分批写入\n" +
                        "       for (int i =0; i< list.size(); i++) {\n" +
                        "           subList.add(list.get(i));\n" +
                        "           if (subList.size() >= batchSize){\n" +
                        "               int num1 = "+sid+"Dao.import"+id+"(subList);\n" +
                        "               insertCount +=num1;\n" +
                        "               subList.clear();\n" +
                        "           }\n"+
                        "       }\n"+
                        "\n" +
                        "\n" +
                        "       //剩余全部写入\n" +
                        "       if (!subList.isEmpty()){\n"+
                        "           int num = "+sid+"Dao.import"+id+" (subList);\n" +
                        "           insertCount +=num; \n"+
                        "           subList.clear();\n" +
                        "       }\n" +
                        "\n" +
                        "       list.clear();\n" +
                        "\n" +
                        "       msg = String.format(\"本次导入数据【%d】条，存在重复数据【%d】条,过滤后最终导入的数据为【%d】条! \","+
                                "sumCount, sumCount - insertCount, insertCount); \n" +
                        "       log.info(\"本次导入数据【{}】条,存在重复数据【{}】条,过滤后最终导入的数据为【{}】条!\","+
                                "sumCount, sumCount - insertCount, insertCount);\n"+
                        "\n\n"+
                        "   }\n\n" +
                        "   public String getMsg() {\n" +
                        "       return msg;\n" +
                        "   }\n\n" +
                        "   public int getBatchSize(Class clazz){\n" +
                        "       return 32767 / clazz.getDeclaredFields().length;\n" +
                        "   }\n"+
                        "\n"+
                        "}\n";
        File fileDirectory = new File(absolutePath);
        if (!fileDirectory.exists()) {
            System.out.println("Listener导入目录不存在,新建一个");
            fileDirectory.mkdirs();
        }
        File file = new File(absolutePath + id + "Listener.java");
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(str);
        fileWriter.flush();
        System.out.println("genListener finish");

    }

    private static void genImportBo(String id, String name, HashMap<String, StringBuilder> map) throws IOException {
        StringBuilder importBoBuilder = map.get("importBoBuilder");
        String property = System. getProperty("user.dir");
        String path = handleFilePath(POJO+"."+BO);
        String absolutePath = property+path;
        String po =
                        "package "+handlePackage(POJO+"."+BO)+";\n\n"+
                        "import com.alibaba.excel.annotation.ExcelProperty;\n" +
                        "import io.swagger.annotations.ApiModel;\n" +
                        "import lombok.*;\n" +
                        "import java.io.Serializable;\n\n" +
                        "@ApiModel(\""+name+"利用easyExcel导入excel映射体\")\n"+
                        "@Data\n" +
                        "@Builder\n" +
                        "@EqualsAndHashCode\n"+
                        "@NoArgsConstructor\n"+
                        "@AllArgsConstructor\n" +
                        "public class Import"+id+"Bo implements Serializable {\n\n"+
                                importBoBuilder.toString()+
                        "}\n";

            File fileDirectory = new File(absolutePath);
            if (!fileDirectory.exists()) {
                System.out.println("ImportBo导入目录不存在,新建一个");
                fileDirectory.mkdirs();
            }
            File file = new File(absolutePath + "Import"+id + "Bo.java");
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(po);
            fileWriter.flush();
            System.out.println("genImportBo finish");
    }

    private static void genImportVo(String id, String name) throws IOException {
        String property = System.getProperty("user.dir");
        String path = handleFilePath(POJO+"."+VO);
        String absolutePath = property+path;
        String po =
                "package "+handlePackage(POJO+"."+VO)+";\n\n"+
                "import io.swagger.annotations.ApiModel;\n" +
                "import io.swagger.annotations.ApiModelProperty;\n" +
                "import lombok.AllArgsConstructor;\n"+
                "import lombok.Data;\n" +
                "import lombok.NoArgsConstructor;\n"+
                "import org.springframework.web.multipart.MultipartFile;\n" +
                "\n" +
                "import javax.validation.constraints.NotNull;\n" +
                "\n" +
                "@ApiModel(\""+name +"批次导入请求体\")\n"+
                "@Data\n"+
                "@NoArgsConstructor\n"+
                "@AllArgsConstructor\n"+
                "public class Import"+id+"Vo {\n" +
                "\n" +
                "   @ApiModelProperty(value = \"导入的文件。文件类型excel\")\n" +
                "   @NotNull(message =(\"导入的文件不能为空\")\n" +
                "   private MultipartFile file;\n" +
                "   \n" +
                "}\n";

                File fileDirectory = new File(absolutePath);
                if (!fileDirectory.exists()) {
                    System.out.println("ImportVo导入目录不存在,新建一个");
                    fileDirectory.mkdirs();
                }
                File file = new File(absolutePath + "Import"+id + "Vo.java");
                FileWriter fileWriter = new FileWriter(file);
                fileWriter.write(po);
                fileWriter.flush();
                System.out.println("genImportVo finish");
    }

    public static void getContent(HashMap<String, StringBuilder> map, String driver,
                                  String url, String username, String password,
                                  String dataTable, String schema, boolean isSwaggerFlag,
                                  boolean isMybatisPlusFlag, String databaseType) {
        Connection connection = null;
        StringBuilder poBuilder = new StringBuilder();//表对应实体类，字段相同不做拓展
        StringBuilder boBuilder = new StringBuilder();//自定义实体类，字段相同可拓展
        StringBuilder selectBuilder = new StringBuilder();
        StringBuilder insertBuilder = new StringBuilder();
        StringBuilder insertForeachBuilder = new StringBuilder();
        StringBuilder updateBuilder = new StringBuilder();
        StringBuilder exportBoBuilder = new StringBuilder();
        StringBuilder importBoBuilder = new StringBuilder();
        StringBuilder exportExcelTableHeadStrBuilder = new StringBuilder();//生成导出模板excel文件表头字符串
        StringBuilder exportExcelTableExpressionStrBuilder = new StringBuilder();//生成导出模板excel文件数据填充表达式字符串
        StringBuilder importExcelTableHeadStrBuilder = new StringBuilder();//生成导入模板excel文件表头字符串
        selectBuilder.append("\n ");
        int resultNum = 1;
        int importFieldNum = 0;

        //填充properties文件中#{}参数
        Map<String, String> placeholders = new HashMap<>();
        placeholders.put("table", dataTable);
        placeholders.put("schema", schema);
        placeholders.put("order", "asc");

        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url, username, password);
            if (connection != null) {
                System.out.println("数据库连接成功!");
            }

            String sql = "";

            if ("mysql".equals(databaseType)){
                sql = PropertiesUtils.getReplacedValue("mysql.properties", "sql.select", placeholders,handleFilePath(UTILS));
            }else if ("postgresql".equals(databaseType)){
                sql = PropertiesUtils.getReplacedValue("postgresql.properties", "sql.select", placeholders,handleFilePath(UTILS));
            }else if ("oracle".equals(databaseType)){
                sql = PropertiesUtils.getReplacedValue("oracle.properties", "sql.select", placeholders,handleFilePath(UTILS));
            }else {
                System.out.println("未知数据库!请检查");
            }

            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                String columnName = resultSet.getString("column_name");
                String dataType = resultSet.getString("data_type");
                String numericScale = resultSet.getString("numeric_scale");
                String columnComment = resultSet.getString("column_comment");//数据表注释字段
                if (columnComment==null||columnComment.isEmpty()) {
                    columnComment = "未注释字段";
                }
                String annoName = columnName; //@TableField注解中的値，对应数据库字段名
                String name = columnName.toLowerCase();//经过驼峰后的成员变量名称
                String type = dataType;//成员变量类型
                String point = numericScale;//用来成员变量类型是Integer还是BigDecimal
                Pattern pattern_ = Pattern.compile("_");
                Matcher matcher_ = pattern_.matcher(name);
                while (matcher_.find()) {
                    int start = matcher_.start();
                    //忽略第一个和最后一个下划线
                    if (start == 0 || start == name.length() - 1) {
                        continue;
                    }
                    StringBuilder stringBuilder = new StringBuilder(name);
                    String olds = String.valueOf(name.charAt(start + 1));
                    String news = olds.toUpperCase();
                    //下划线后一个字母小写变大写
                    name = stringBuilder.replace(start + 1, start + 2, news).toString();
                }
                name = name.replace("_", "");
                if ("mysql".equals(databaseType)){
                    if ("decimal".equals(type) && !"0".equals(point)) {
                        type = "BigDecimal";
                    } else if ("varchar".equals(type) && point == null) {
                        type = "String";
                    } else if ("int".equals(type) && "0".equals(point)) {
                        type = "Integer";
                    } else {
                        type = "String";
                    }
                }else if ("postgresql".equals(databaseType)){
                    if ("numeric".equals(type) && !"0".equals(point)) {
                        type = "BigDecimal";
                    } else if ("character varying".equals(type) && point == null) {
                        type = "String";
                    } else if ("0".equals(point)) {
                        type = "Integer";
                    } else {
                        type = "String";
                    }
                }else if ("oracle".equals(databaseType)){
                    if ("NUMBER".equals(type)&& !"0".equals(point)) {
                        type = "BigDecimal";
                    } else if ("VARCHAR2".equals(type)||"VARCHAR".equals(type)) {
                        type = "String";
                    } else if ("0".equals(point)) {
                        type = "Integer";
                    } else {
                        type = "String";
                    }
                }else {

                }

                //用作导入导出模板和相对应实体类
                String tempStr = columnComment.equals("'未注释字段") ? name : columnComment;
				String annoUp = "";
				if (isMybatisPlusFlag){
					annoUp = "\t@TableField(\"" + annoName + "\")" + "\n";
				}
                String proLow = "\tprivate " + type + " " + name + ";" + "\n\n";
                String commentPo = "\t/**\n" +
                        "\t*" + columnComment + "\n" +
                        "\t*/\n";
				String commentBo = "";
				if (isSwaggerFlag){
					commentBo = "\t@ApiModelProperty(value = \"" + columnComment + "\")" + "\n";
				}
                String easyExcelExportBo = "\t@ExcelProperty(\"" + tempStr + "\")" + "\n";
                String easyExcelImportBo = "\t@ExcelProperty(index = " + importFieldNum + ",value =\"" + tempStr + "\")\n";

                String proLowBo = "\tprivate String " + name + ";" + "\n\n";
                poBuilder.append(commentPo).append(annoUp).append(proLow);
                boBuilder.append(commentBo).append(proLowBo);
                exportBoBuilder.append(easyExcelExportBo).append(proLowBo);
                importBoBuilder.append(easyExcelImportBo).append(proLowBo);
                selectBuilder.append("\t").append("\t").append("\t").append("\t").
                        append(annoName).append(" as ").append(name).append(",\n");
                updateBuilder.append("\t").append("\t").append("\t").append("\t").
                        append(annoName).append(" =#{item.").append(name).append("},\n");

                exportExcelTableHeadStrBuilder.append(tempStr).append("\t");
                importExcelTableHeadStrBuilder.append(tempStr).append("\t");
                exportExcelTableExpressionStrBuilder.append("{.").append(name).append("}").append("\t");
                if (resultNum % 4 == 0) {
                    insertBuilder.append(annoName).append(",\n\t\t");
                    insertForeachBuilder.append(name).append(",\n\t\t");
                } else {
                    insertBuilder.append(annoName).append(",");
                    insertForeachBuilder.append(name).append(",");
                }

                resultNum++;
                importFieldNum++;
            }
            map.put("poBuilder", poBuilder);
            map.put("boBuilder", boBuilder);
            map.put("selectBuilder", selectBuilder);
            map.put("insertBuilder", insertBuilder);
            map.put("insertForeachBuilder", insertForeachBuilder);
            map.put("updateBuilder", updateBuilder);
            map.put("exportBoBuilder", exportBoBuilder);
            map.put("importBoBuilder", importBoBuilder);
            map.put("exportExcelTableHeadStrBuilder", exportExcelTableHeadStrBuilder);
            map.put("exportExcelTableExpressionStrBuilder", exportExcelTableExpressionStrBuilder);
            map.put("importExcelTableHeadStrBuilder", importExcelTableHeadStrBuilder);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private static String handleFilePath(String suffix){
        return (fileFromParent+suffix).replace(".", "\\")+"\\";
    }
    private static String handlePackage(String suffix){
        return java2package+suffix;
    }
    private static String handleMapperPath(String suffix){
        return (mapperFromParent+suffix).replace(".", "\\")+"\\";
    }

    /**
     * 在文件中倒序查找第一个包含目标字符串的行，并在其后插入多行内容
     *
     * @param filePath      文件路径
     * @param targetString  要查找的目标字符串（会在每一行的内容中查找是否包含它）
     * @param linesToInsert 要插入的多行内容（List<String>，每行可以带换行符，也可不带）
     * @throws IOException 如果读写文件出错
     */
    public static void insertLinesAfterFirstMatchFromEnd(
            String filePath,
            String targetString,
            List<String> linesToInsert
    ) throws IOException {
        // 1. 读取文件所有行
        List<String> lines = Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8);

        // 2. 倒序遍历，查找第一个包含目标字符串的行
        int insertAfterIndex = -1;
        for (int i = lines.size() - 1; i >= 0; i--) {
            String line = lines.get(i);
            if (line.contains(targetString)) {
                insertAfterIndex = i;
                break;
            }
        }

        if (insertAfterIndex == -1) {
            System.out.println("未找到包含目标字符串 \"" + targetString + "\" 的行，不进行插入。");
            return;
        }

//        System.out.printf("找到目标字符串 \"%s\" 在第 %d 行，准备在其前面插入 %d 行内容。\n",
//                targetString, insertAfterIndex , linesToInsert.size());

        // 3. 创建新的行列表，并在目标行前面插入新行
        List<String> newLines = new ArrayList<>(lines);
        newLines.addAll(insertAfterIndex, linesToInsert);

        // 4. 将修改后的内容写回原文件（覆盖）
        Files.write(Paths.get(filePath), newLines, StandardCharsets.UTF_8);

        System.out.println("已成功插入多行内容。");
    }

}
